home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / library / mfssrgrp.lha / usergroup / usergroup.c < prev   
Text File  |  1992-09-02  |  23KB  |  736 lines

  1. RCS_ID_C="$Id: usergroup.c,v 4.1 1994/05/16 14:09:07 ppessi Exp $";
  2. /*
  3.  * Author: ppessi <Pekka.Pessi@hut.fi>
  4.  *
  5.  * This file is part of the AmiTCP/IP UserGroup Library.
  6.  *
  7.  * Copyright © 1993 AmiTCP/IP Group, <AmiTCP-Group@hut.fi>
  8.  *                  Helsinki University of Technology, Finland.
  9.  *
  10.  * Created      : Sun Nov 28 17:45:55 1993 ppessi
  11.  * Last modified: Mon May 16 14:33:00 1994 ppessi
  12.  *
  13.  * $Log: usergroup.c,v $
  14.  * Revision 4.1  1994/05/16  14:09:07  ppessi
  15.  * Release 4
  16.  *
  17.  * Revision 3.1  1994/02/24  16:49:34  ppessi
  18.  * Release 3.
  19.  *
  20.  * Revision 2.2  1994/02/17  02:21:58  ppessi
  21.  * *** empty log message ***
  22.  *
  23.  * Revision 2.1  1994/01/23  03:23:23  ppessi
  24.  * Cleaned documentation. Added licence.
  25.  * Modified the errno pointer tags; there is now a separate tag
  26.  * for each legal errno size.
  27.  * Activated the UGT_OWNER code.
  28.  *
  29.  * Revision 1.3  1994/01/21  08:12:22  ppessi
  30.  * Added _ProgramName as first argument of ug_SetupContext()
  31.  *
  32.  * Revision 1.2  1994/01/20  08:28:13  ppessi
  33.  * Changed the ug_StrError slightly, an device error code is now also
  34.  * accepted.
  35.  *
  36.  * Revision 1.1  94/01/19  10:05:08  ppessi
  37.  * Initial revision
  38.  *
  39.  */
  40.  
  41. /****** usergroup.library/--background-- ***********************************
  42.  
  43.     WARNING
  44.         Unfortunately, this experimental release of usergroup.library is not
  45.         compatible with multiuser.library.  There are some problems with
  46.         multiuser.library, eg. the multiuser.library does not support the
  47.         real ids.  Also the password format is different, multiuser.library
  48.         uses the AS225r2 password format, which is very simple encoding.
  49.         The usergroup.library uses the standard Unix password encryption.
  50.  
  51.         The current implementation of this model is very simple.  All tasks
  52.         belong to one session and they share common credentials.  The
  53.         setsid() function call does nothing.  You are supposed to log in
  54.         using "login -f login-name" when the machine is booted.
  55.  
  56.     PURPOSE
  57.         When the AmiTCP/IP was originally released, a little attention was
  58.         paid to the security aspects.  Since the AmigaOS is basically a
  59.         single user operating system with little or no provisions for
  60.         multiple users, there was no standard how accounts, password
  61.         checking and access control should be implemented.
  62.  
  63.     USERGROUP.LIBRARAY SEMANTICS
  64.         The usergroup.library provides a BSD-stylish interface to the user
  65.         and group identification, the account database, the group databases,
  66.         password checking and login information.  Since it is a shared
  67.         library instead of link library, the underlying security mechanisms
  68.         can be changed according future standards and needs.  The
  69.         usergroup.library provides quite clean basic model. Each process has
  70.         credentials, which consist of real used ID, real group ID, effective
  71.         user ID and up to 32 effective group IDs. The process credentials
  72.         can be changed with setuid()/setgid()/setgroups() functions.
  73.  
  74.         Each process belongs also to an session.  A new session will created
  75.         with setsid() function call, which is typically executed before you
  76.         call command or when you create a new connection.  A session
  77.         contains the login name of the user and possibly some other
  78.         information.
  79.  
  80.     The information about users logging in and out is typically stored
  81.         into a file in Unix systems.  These files (in BSD Net2 release they
  82.         are /var/run/utmp and /var/log/wtmp) are usually very long and
  83.         contain holes.  Since the AmigaDOS files cannot contain holes, this
  84.         approach is not practical.  The usergroup.library provides an
  85.         loosely HP-UX-stylish interface to the utmp and lastlogin databases.
  86.         The utmp database contains an entry for each session, it is searched
  87.         in linear manner qith getutent().  The lastlogin database contains
  88.         an entry for each user and getlastlogin() returns an entry for given
  89.         UID.
  90.  
  91.         The usergroup.library does not directly depend on AmiTCP/IP.  It can
  92.         be used with any program needing user identification, account and
  93.         group databases.
  94.     
  95.     USING USERGROUP.LIBRARY
  96.         Each time the usergroup.library is opened, it creates an new
  97.         instance of the library base.  The library base contains the static
  98.         data buffers used by many library functions.  The usergroup.library
  99.         functions behave exactly like they were in link library. The
  100.         functions allocate all resources for you, the library also frees the
  101.         resources when they are no more needed.
  102.  
  103.     Since each library contains static data and resources allocated in
  104.         the context of calling task (ie. signals), only the task which
  105.         opened the library is allowed to call most library functions.
  106.         However, any task whatsoever can call following functions:
  107.  
  108.             getuid() geteuid() getgid() getegid() getsid()
  109.  
  110.         These functions return the credentials of calling task.
  111.  
  112.         It is also possible to call following functions from any task.
  113.         However, note that a non-owning tasks cannot recover error codes:
  114.  
  115.             getgroups() setreuid() setuid() setregid() setgid() setgroups() 
  116.         setsid() setlogin() 
  117.  
  118.         It is possible to give the library instance to another task.  Only
  119.         the current owner can close the library.
  120.  
  121.         The user and group information is provided by netinfo.device.
  122.         It is more convenient interface to user and group databases
  123.         for multitasking applications.
  124.  
  125.     EXAMPLE PROGRAMS
  126.         There are a few utilities provided as examples.  The finger programs
  127.         deals with user (password), utmp and lastlog database, the id and
  128.         whoami with user and group identification, login and passwd with
  129.         password checking and password changing.
  130.  
  131.     SEE ALSO
  132.         netinfo.device/--background--, ug_SetupContextTags(),
  133.         SAS C Manual, libinit.c and libinitr.o
  134.  
  135.     COPYRIGHT
  136.         Copyright © 1980--1991 The Regents of the University of California.
  137.         Copyright © 1993, 1994 AmiTCP/IP-Group, <AmiTCP-Group@hut.fi>,
  138.         Helsinki University of Technology, Finland.
  139.  
  140. ****************************************************************************
  141. */
  142.  
  143. /****** usergroup.library/--Licence-- **************************************
  144.  
  145.    USERGROUP.LIBRARY LICENCE
  146.         The usergroup.library is Copyright © 1993, 1994 AmiTCP/IP-Group,
  147.         <AmiTCP-Group@hut.fi>, Helsinki University of Technology, Finland.
  148.  
  149.         The usergroup.library contains source code from 4.3BSD Net2 release.
  150.         The 4.3BSD Net2 release is copyright © 1980 --- 1991 The Regents of
  151.         the University of California.  The following licence apply to the
  152.         usergroup.library and its documentation:
  153.  
  154.         Redistribution and use in source and binary forms, with or without
  155.         modification, are permitted provided that the following conditions
  156.         are met:
  157.  
  158.         1. Redistributions of source code must retain the above copyright
  159.            notice, this list of conditions and the following disclaimer.
  160.         2. Redistributions in binary form must reproduce the above copyright
  161.            notice, this list of conditions and the following disclaimer in
  162.            the documentation and/or other materials provided with the
  163.            distribution.
  164.         3. All advertising materials mentioning features or use of this
  165.            software must display the following acknowledgement: This product
  166.            includes software developed by the University of California,
  167.            Berkeley and its contributors.
  168.         4. Neither the name of the University nor the names of its
  169.            contributors may be used to endorse or promote products derived
  170.            from this software without specific prior written permission.
  171.  
  172.         THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
  173.         AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  174.         TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  175.         PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR
  176.         CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  177.         SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  178.         LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  179.         USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  180.         ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  181.         OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  182.         OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  183.         SUCH DAMAGE.
  184.  
  185. ****************************************************************************
  186. */
  187.  
  188.  
  189. #include "base.h"
  190. #include "libfunc.h"
  191.  
  192. #include <exec/memory.h>
  193.  
  194. #include <assert.h>
  195.  
  196. #include <sys/errno.h>
  197. #include <exec/errors.h>
  198. #include "credential.h"
  199.  
  200. struct ExecBase *SysBase;
  201. struct DosLibrary *DOSBase;
  202. struct Library *UtilityBase;
  203.  
  204. #ifndef UTILITY_TAGITEM_H
  205. #include <utility/tagitem.h>
  206. #endif
  207. #include <proto/utility.h>
  208.  
  209. extern struct Process*owner;
  210. static void CleanupNIO(void);
  211. int TimeInit(void);
  212. void TimeCleanup(void);
  213.  
  214. ASM void __UserLibCleanup(void);
  215.  
  216. /*
  217.  * Library initialization
  218.  */
  219. SAVEDS ASM int __UserLibInit(void)
  220. {
  221.   SysBase = *(struct ExecBase **)4;
  222.  
  223.   InitSemaphore(ni_lock);
  224.  
  225.   if ((DOSBase = (void *)OpenLibrary("dos.library", 37L)) &&
  226.       (UtilityBase = OpenLibrary("utility.library", 37L)) &&
  227.       TimeInit() == 0 && LRandomInit() == 0) {
  228.     owner = (struct Process *)FindTask(NULL);
  229.     Forbid();
  230.     if (!(CredentialBase = OpenResource(CREDENTIALNAME))) {
  231.       CredentialBase = CredentialInit("root");
  232.     }
  233.     Permit();
  234.     if (CredentialBase)
  235.       return 0;
  236.   }
  237.  
  238.   __UserLibCleanup();
  239.  
  240.   return -1;
  241. }
  242.  
  243. SAVEDS ASM void __UserLibCleanup(void)
  244. {
  245.   CleanupUTMP();
  246.   CleanupNIO();
  247.   TimeCleanup();
  248.   if (DOSBase)
  249.     CloseLibrary((void *)DOSBase);
  250.   if (UtilityBase)
  251.     CloseLibrary(UtilityBase);
  252. }
  253.  
  254. /*
  255.  * Errno handling
  256.  */
  257. ULONG break_mask = 0L;
  258. int internal_errno;
  259. void *errnop = NULL;
  260. errnop_t errnosize;
  261.  
  262. /*
  263.  * Set errno
  264.  */
  265. void SetErrno(int errno)
  266. {
  267.   internal_errno = errno;
  268.  
  269.   if (errnop)
  270.     switch (errnosize) {
  271.     case es_byte:
  272.       *(UBYTE *)errnop = errno;
  273.       break;
  274.     case es_word:
  275.       *(UWORD *)errnop = errno;
  276.       break;
  277.     case es_long:
  278.       *(ULONG *)errnop = errno;
  279.       break;
  280.     }
  281. }
  282.  
  283. /****** usergroup.library/ug_GetErr ****************************************
  284.  
  285.     NAME
  286.         ug_GetErr - get current error code
  287.  
  288.     SYNOPSIS
  289.         error = ug_GetErr(void)
  290.          D0
  291.  
  292.         int ug_GetErr(void)
  293.  
  294.     FUNCTION
  295.         Most usergroup.library functions return -1 to indicate an error.
  296.         When this happens (or whatever the defined error return for the
  297.         routine) this routine may be called to determine more information.
  298.         The default startup function will redirect the error codes also into
  299.         the global variable `errno'.
  300.  
  301.         Note: there is no guarantee as to the value returned from ug_GetErr()
  302.         after a successful operation.
  303.  
  304.     RESULTS
  305.         error - error code
  306.  
  307.     SEE ALSO
  308.         ug_StrError(), ug_SetupContextTags(), dos.library/IoErr()
  309.  
  310. ****************************************************************************
  311. */
  312.  
  313. /*
  314.  * Get errno
  315.  */
  316. SAVEDS ASM int R_ug_GetErr(void)
  317. {
  318.   return internal_errno;
  319. }
  320.  
  321. /*
  322.  * Handle the netinfo device
  323.  */
  324. struct SignalSemaphore ni_lock[1];
  325. struct Process *owner;
  326. static struct MsgPort *niport;
  327. static struct NetInfoReq *nireq;
  328.  
  329. static struct Device *nidevice[2];
  330. static APTR niunit[2];
  331. static APTR nibuffer[2];
  332.  
  333. struct NetInfoReq *OpenNIUnit(ULONG unit)
  334. {
  335.   /* Check ownership */
  336.   if (owner != (struct Process *)FindTask(NULL)) {
  337.     SetErrno(EDEADLK);
  338.     return NULL;
  339.   }
  340.  
  341.   /* Allocate port */
  342.   if (niport == NULL) {
  343.     niport = CreateMsgPort();
  344.     if (niport == NULL)
  345.       return NULL;
  346.   }
  347.   if (nireq == NULL) {
  348.     nireq = CreateIORequest(niport, sizeof(*nireq));
  349.  
  350.     if (nireq == NULL)
  351.       return NULL;
  352.   }
  353.  
  354.   if (nidevice[unit]) {
  355.     /* Already opened */
  356.     nireq->io_Device = nidevice[unit];
  357.     nireq->io_Unit = niunit[unit];
  358.   } else {
  359.     if (OpenDevice(NETINFONAME, unit, (struct IORequest *)nireq, 0L)) {
  360.       return NULL;
  361.     }
  362.  
  363.     nidevice[unit] = nireq->io_Device;
  364.     niunit[unit] = nireq->io_Unit;
  365.   }
  366.  
  367.   if (nibuffer[unit] == NULL) {
  368.     nibuffer[unit] = AllocVec(MAXLINELEN, MEMF_PUBLIC);
  369.     if (nibuffer[unit] == NULL)
  370.       return NULL;
  371.   }
  372.  
  373.   nireq->io_Length = MAXLINELEN;
  374.   nireq->io_Data = nibuffer[unit];
  375.  
  376.   return nireq;
  377. }
  378.  
  379. void CloseNIUnit(ULONG unit)
  380. {
  381.   ObtainSemaphore(ni_lock);
  382.  
  383.   if (nidevice[unit]) {
  384.     assert(nireq != NULL);
  385.  
  386.     nireq->io_Device = nidevice[unit];
  387.     nireq->io_Unit = niunit[unit];
  388.  
  389.     CloseDevice(nireq);
  390.  
  391.     nidevice[unit] = NULL;
  392.     niunit[unit] = NULL;
  393.   }
  394.  
  395.   ReleaseSemaphore(ni_lock);
  396. }
  397.  
  398. static void CleanupNIO(void)
  399. {
  400.   R_endpwent();
  401.   R_endgrent();
  402.  
  403.   if (nibuffer[NETINFO_PASSWD_UNIT] != NULL)
  404.     FreeVec(nibuffer[NETINFO_PASSWD_UNIT]);
  405.   nibuffer[NETINFO_PASSWD_UNIT] = NULL;
  406.  
  407.   if (nibuffer[NETINFO_GROUP_UNIT] != NULL)
  408.     FreeVec(nibuffer[NETINFO_GROUP_UNIT]);
  409.   nibuffer[NETINFO_GROUP_UNIT] = NULL;
  410.  
  411.   if (nireq)
  412.     DeleteIORequest(nireq), nireq = NULL;
  413.  
  414.   if (niport)
  415.     DeleteMsgPort(niport), niport = NULL;
  416. }
  417.  
  418. BYTE myDoIO(struct NetInfoReq *req)
  419. {
  420.   DoIO(req);
  421.   return req->io_Error;
  422. }
  423.  
  424. static const BYTE ioerr2errno[-IOERR_SELFTEST] = {
  425.   /* IOERR_OPENFAIL */
  426.   ENOENT,
  427.   /* IOERR_ABORTED */
  428.   EINTR,
  429.   /* IOERR_NOCMD */
  430.   ENODEV,
  431.   /* IOERR_BADLENGTH */
  432.   EBUSY,
  433.   /* IOERR_BADADDRESS */
  434.   EFAULT,
  435.   /* IOERR_UNITBUSY */
  436.   EBUSY,
  437.   /* IOERR_SELFTEST */
  438.   ENXIO,
  439. };
  440.  
  441. void SetDeviceErr(void)
  442. {
  443.   short err;
  444.  
  445.   if (nireq)
  446.     err = nireq->io_Error;
  447.   else
  448.     err = ENOMEM;
  449.  
  450.   if (err < 0) {
  451.     if (err >= IOERR_SELFTEST)
  452.       err = ioerr2errno[-1 - err];
  453.     else
  454.       err = EIO;
  455.   }
  456.  
  457.   SetErrno(err);
  458. }
  459.  
  460. /*
  461.  * Get error string
  462.  */
  463. #define EUNKNOWN "Unknown error"
  464.  
  465. static const char * const __ug_errlist[] = {
  466.   "Undefined error: 0",              /*  0 - ENOERROR */
  467.   "Operation not permitted",          /*  1 - EPERM */
  468.   "No such entry",              /*  2 - ENOENT */
  469.   "No such process",                  /*  3 - ESRCH */
  470.   "Interrupted library call",          /*  4 - EINTR */
  471.   "Input/output error",              /*  5 - EIO */
  472.   "Device not configured",          /*  6 - ENXIO */
  473.   "Argument list too long",          /*  7 - E2BIG */
  474.   "Exec format error",              /*  8 - ENOEXEC */
  475.   "Bad file descriptor",          /*  9 - EBADF */
  476.   "No child processes",              /* 10 - ECHILD */
  477.   "Resource deadlock avoided",              /* 11 - EDEADLK */
  478.   "Cannot allocate memory",          /* 12 - ENOMEM */
  479.   "Permission denied",              /* 13 - EACCES */
  480.   "Bad address",              /* 14 - EFAULT */
  481.   "Block device required",          /* 15 - ENOTBLK */
  482.   "Device busy",              /* 16 - EBUSY */
  483.   "File exists",              /* 17 - EEXIST */
  484.   "Cross-device link",              /* 18 - EXDEV */
  485.   "Operation not supported by device",      /* 19 - ENODEV */
  486.   "Not a directory",              /* 20 - ENOTDIR */
  487.   "Is a directory",              /* 21 - EISDIR */
  488.   "Invalid argument",              /* 22 - EINVAL */
  489.   "Too many open files in system",      /* 23 - ENFILE */
  490.   "Too many open files",          /* 24 - EMFILE */
  491.   "Inappropriate operation for device",   /* 25 - ENOTTY */
  492.   "Text file busy",              /* 26 - ETXTBSY */
  493.   "File too large",              /* 27 - EFBIG */
  494.   "No space left on device",          /* 28 - ENOSPC */
  495.   "Illegal seek",              /* 29 - ESPIPE */
  496.   "Read-only file system",          /* 30 - EROFS */
  497.   "Too many links",              /* 31 - EMLINK */
  498.   "Broken pipe",              /* 32 - EPIPE */
  499.  
  500.   /* math software */
  501.   "Numerical argument out of domain",      /* 33 - EDOM */
  502.   "Result too large",              /* 34 - ERANGE */
  503. /* non-blocking and interrupt i/o */
  504.   "Resource temporarily unavailable",      /* 35 - EAGAIN */
  505.                       /* 35 - EWOULDBLOCK */
  506.   "Operation now in progress",          /* 36 - EINPROGRESS */
  507.   "Operation already in progress",      /* 37 - EALREADY */
  508.  
  509. /* ipc/network software -- argument errors */
  510.   "Socket operation on non-socket",      /* 38 - ENOTSOCK */
  511.   "Destination address required",      /* 39 - EDESTADDRREQ */
  512.   "Message too long",              /* 40 - EMSGSIZE */
  513.   "Protocol wrong type for socket",      /* 41 - EPROTOTYPE */
  514.   "Protocol not available",          /* 42 - ENOPROTOOPT */
  515.   "Protocol not supported",          /* 43 - EPROTONOSUPPORT */
  516.   "Socket type not supported",          /* 44 - ESOCKTNOSUPPORT */
  517.   "Operation not supported",          /* 45 - EOPNOTSUPP */
  518.   "Protocol family not supported",      /* 46 - EPFNOSUPPORT */
  519.                       /* 47 - EAFNOSUPPORT */
  520.   "Address family not supported by protocol family",
  521.   "Address already in use",          /* 48 - EADDRINUSE */
  522.   "Can't assign requested address",      /* 49 - EADDRNOTAVAIL */
  523.  
  524. /* ipc/network software -- operational errors */
  525.   "Network is down",              /* 50 - ENETDOWN */
  526.   "Network is unreachable",          /* 51 - ENETUNREACH */
  527.   "Network dropped connection on reset",  /* 52 - ENETRESET */
  528.   "Software caused connection abort",      /* 53 - ECONNABORTED */
  529.   "Connection reset by peer",          /* 54 - ECONNRESET */
  530.   "No buffer space available",          /* 55 - ENOBUFS */
  531.   "Socket is already connected",      /* 56 - EISCONN */
  532.   "Socket is not connected",          /* 57 - ENOTCONN */
  533.   "Can't send after socket shutdown",      /* 58 - ESHUTDOWN */
  534.   "Too many references: can't splice",      /* 59 - ETOOMANYREFS */
  535.   "Connection timed out",          /* 60 - ETIMEDOUT */
  536.   "Connection refused",              /* 61 - ECONNREFUSED */
  537.  
  538.   "Too many levels of symbolic links",      /* 62 - ELOOP */
  539.   "File name too long",              /* 63 - ENAMETOOLONG */
  540.  
  541. /* should be rearranged */
  542.   "Host is down",              /* 64 - EHOSTDOWN */
  543.   "No route to host",              /* 65 - EHOSTUNREACH */
  544.   "Directory not empty",          /* 66 - ENOTEMPTY */
  545. };
  546.  
  547. static const int __ug_nerr = ENOTEMPTY + 1;
  548.  
  549. /****** usergroup.library/ug_StrError **************************************
  550.  
  551.     NAME
  552.         ug_StrError - Return the text associated with error code
  553.  
  554.     SYNOPSIS
  555.         text = ug_StrError(code)
  556.          D0                   D1
  557.  
  558.         const char *ug_StrError(LONG);
  559.  
  560.     FUNCTION
  561.         The strerror() function maps the error number specified by the
  562.         errnum parameter to a language-dependent error message string, and
  563.         returns a pointer to the string.  The string pointed to by the
  564.         return value should not be modified by the program, but may be
  565.         overwritten by a subsequent call to this function.
  566.  
  567.     INPUTS
  568.         code - error code returned by ug_GetErr() function.
  569.  
  570.     RESULT
  571.         text - text associated with the error code.
  572.  
  573.     NOTES
  574.         The current implementation will understands also the negative IO
  575.         error codes.
  576.  
  577.     BUGS
  578.         Currently only language available is English.
  579.  
  580.     SEE ALSO
  581.         ug_GetErr()
  582.  
  583. ******************************************************************************
  584. */
  585.  
  586. SAVEDS ASM const char *R_ug_StrError(REG(d1) LONG code)
  587. {
  588.   if (code < 0) {
  589.     if (code >= IOERR_SELFTEST)
  590.       code = ioerr2errno[-1 - code];
  591.     else
  592.       code = EIO;
  593.   }
  594.  
  595.   if (code >= __ug_nerr)
  596.     return EUNKNOWN;
  597.   else
  598.     return __ug_errlist[code];
  599. }
  600.  
  601. /****** usergroup.library/ug_SetupContextTags ********************************
  602.  
  603.     NAME
  604.         ug_SetupContextTagList - Set up the caller context
  605.         ug_SetupContextTags    -  varargs stub for ug_SetupContextTagList
  606.  
  607.     SYNOPSIS
  608.         success = ug_SetupContextTagList(taglist)
  609.           D0                               A1
  610.  
  611.         ULONG ug_SetupContextTagList(struct TagItem *);
  612.  
  613.         success = ug_SetupContextTags(...)
  614.  
  615.         ULONG ug_SetupContextTags(LONG tag, ...);
  616.  
  617.  
  618.     FUNCTION
  619.         The function ug_SetupContextTags() will prepare the library caller
  620.         context.
  621.  
  622.     INPUTS
  623.         taglist - pointer to taglist
  624.  
  625.         Currently, there are defined tags as follows:
  626.  
  627.         UGT_ERRNOPTR  - gives the pointer to the errno variable.  The error
  628.                         variable is redirected to the scope of the task.  If
  629.                         the pointer is NULL, no redirection is done anymore.
  630.  
  631.         UGT_ERRNOSIZE - specifies the size of the errno variable. Legal
  632.                         values are 1, 2 and 4.  The UGT_ERRNOSIZE must be
  633.                         given with same call if the UGT_ERRNOPTR is given a
  634.                         non-NULL value.
  635.  
  636.         UGT_INTRMASK  - specifies the interrupt signal mask. All blocking
  637.                         library calls will be interrrupted when a signal in
  638.                         the break mask is received. The signals in the
  639.                         `mask' are not cleared when a library call is
  640.                         interrupted.  The signals in INTRMASK should be
  641.                         allocated in the context of the owning task.
  642.  
  643.         UGT_OWNER     - changes the owner of this library instance.  The
  644.                         UGT_OWNET tagData must be a valid task pointer or
  645.                         NULL. If the pointer is NULL, the library will have
  646.                         no owner and any task can become owner by calling
  647.                         ug_SetupContextTagList(UGT_OWNER, FindTask(NULL),
  648.                         TAG_END) ; 
  649.  
  650.             Most of the library calls are allowed only for the
  651.                         owner of library.  Only the owner can CloseLibrary()
  652.                         this library.
  653.  
  654.     RESULT
  655.         If the call is successfull, value of 0 is returned. Otherwise the
  656.         value -1 is returned. Old context is cleared, if an error occurs.
  657.         The error code can be retrieved with function ug_GetErr().
  658.  
  659.     ERRORS
  660.         [EINVAL]    An illegal input value was specified.
  661.  
  662.     BUGS
  663.         Strange and unusual things will happen if the signal allocated for
  664.         the use of the library is included in the mask.
  665.  
  666.     SEE ALSO
  667.         ug_GetErr(), --background--
  668.  
  669. ******************************************************************************
  670. */
  671.  
  672. const UBYTE *_ProgramName = USERGROUPNAME;
  673.  
  674. SAVEDS ASM int R_ug_SetupContextTagList(REG(a0) const UBYTE *name,
  675.                     REG(a1) struct TagItem *tagargs)
  676. {
  677.   struct TagItem *tag;
  678.   struct Process *caller = (struct Process *)FindTask(NULL);
  679.  
  680.   if (owner != NULL && owner != caller) {
  681.     /* We should */
  682.     InMsg("ug_SetupContextTags: not an owner (%lx)", caller);
  683.     return -1;
  684.   }
  685.  
  686.   if (tagargs == NULL || name == NULL) {
  687.     SetErrno(EINVAL);
  688.     return -1;
  689.   }
  690.  
  691.   _ProgramName = name;
  692.  
  693.   if (tag = FindTagItem(UGT_OWNER, tagargs)) {
  694.     short error;
  695.  
  696.     ObtainSemaphore(ni_lock);
  697.  
  698.     if (owner != NULL && owner != caller) {
  699.       if (tag->ti_Data != NULL) {
  700.     owner = (void *)tag->ti_Data;
  701.     error = 0;
  702.       } else {
  703.     error = EINVAL;
  704.       }
  705.     } else {
  706.       error = EPERM;
  707.     }
  708.  
  709.     ReleaseSemaphore(ni_lock);
  710.  
  711.     if (error) {
  712.       SetErrno(error);
  713.       return -1;
  714.     }
  715.   }
  716.  
  717.   if (tag = FindTagItem(UGT_ERRNOLPTR, tagargs)) {
  718.     errnop = (void *)tag->ti_Data;
  719.     errnosize = es_long;
  720.   }
  721.   if (tag = FindTagItem(UGT_ERRNOWPTR, tagargs)) {
  722.     errnop = (void *)tag->ti_Data;
  723.     errnosize = es_word;
  724.   }
  725.   if (tag = FindTagItem(UGT_ERRNOBPTR, tagargs)) {
  726.     errnop = (void *)tag->ti_Data;
  727.     errnosize = es_byte;
  728.   }
  729.   if (tag = FindTagItem(UGT_INTRMASK, tagargs)) {
  730.     break_mask = tag->ti_Data;
  731.   }
  732.  
  733.   return 0;
  734. }
  735.  
  736.